package com.sc.justification.word;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;

public class WordProcessor {
	private String template = null;
	private Map<String, TextBlock> runMap = new HashMap<String, TextBlock>();
	private XWPFDocument document = null;

	public WordProcessor(String template) {
		super();
		this.template = template;
		findPlaceholders();
	}

	private void findPlaceholders() {
		StringBuilder path = null;
		try {
			path = new StringBuilder();
			document = new XWPFDocument(new FileInputStream(template));
			List<XWPFParagraph> paragraphs = document.getParagraphs();
			for (int i = 0; i < paragraphs.size(); i++) {
				XWPFParagraph xwpfParagraph = paragraphs.get(i);
				path.append("p:" + i);
				searchText(xwpfParagraph, path);
			}

			List<XWPFTable> tables = document.getTables();
			for (int i = 0; i < tables.size(); i++) {
				path = new StringBuilder();
				XWPFTable xwpfTable = tables.get(i);
				path.append("t:" + i);
				// System.out.println(xwpfTable.getText());
				List<XWPFTableRow> xwpfTableRows = xwpfTable.getRows();
				for (int j = 0; j < xwpfTableRows.size(); j++) {
					XWPFTableRow xwpfTableRow = xwpfTableRows.get(j);
					path.append(">row:" + j);
					List<XWPFTableCell> xwpfTableCells = xwpfTableRow
							.getTableCells();
					for (int k = 0; k < xwpfTableCells.size(); k++) {
						XWPFTableCell xwpfTableCell = xwpfTableCells.get(k);
						path.append(">cell:" + k);
						paragraphs = xwpfTableCell.getParagraphs();
						for (int m = 0; m < paragraphs.size(); m++) {
							path.append(">p:" + m);
							XWPFParagraph xwpfParagraph = paragraphs.get(m);
							searchText(xwpfParagraph, path);
							path.delete(path.lastIndexOf(">p:"), path.length());
						}
						path.delete(path.lastIndexOf(">cell:"), path.length());
					}
					path.delete(path.lastIndexOf(">row:"), path.length());
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	private void searchText(XWPFParagraph xwpfParagraph, StringBuilder path) {
		List<XWPFRun> runs = xwpfParagraph.getRuns();
		for (int i = 0; i < runs.size(); i++) {
			XWPFRun xwpfRun = runs.get(i);
			if (xwpfRun.getText(0).matches(".*\\{.+\\}.*")) {
				path.append(">r:" + i);
				TextBlock textBlock = new TextBlock();
				textBlock.setKey(xwpfRun.getText(0));
				textBlock.setPath(path.toString());
				textBlock.setXwpfRun(xwpfRun);
				runMap.put(xwpfRun.getText(0), textBlock);
			}
		}

	}

	public void write(Map<String, String> data, String outputFile) {
		for (Map.Entry<String, String> entry : data.entrySet()) {
			String key = "${" + entry.getKey() + "}";
			TextBlock textBlock = runMap.get(key);
			XWPFRun xwpfRun = textBlock.getXwpfRun();
			xwpfRun.setText(entry.getValue(), 0);
		}
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(outputFile);
			document.write(fos);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public Map<String, String> read(String inputFile) {
		Map<String, String> data = new HashMap<String, String>();
		try {
			XWPFDocument document = new XWPFDocument(new FileInputStream(
					inputFile));
			for (Map.Entry<String, TextBlock> entry : runMap.entrySet()) {
				String key = entry.getKey();
				String path = entry.getValue().getPath();
				XWPFRun xwpfRun = getXWPFRunByPath(document, path);
				String strippedKey=key.substring(2, key.length()-1);
				data.put(strippedKey, xwpfRun.getParagraph().getText());
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		return data;
	}

	private XWPFRun getXWPFRunByPath(XWPFDocument document, String path) {
		if (path.startsWith("p")) {
			String[] nodes = path.split(">");
			String pNode = nodes[0];
			String rNode = nodes[1];
			String[] str = pNode.split(":");
			String pos = str[1];
			XWPFParagraph paragraph = document.getParagraphArray(Integer
					.valueOf(pos));
			str = rNode.split(":");
			pos = str[1];
			XWPFRun xwpfRun = paragraph.getRuns().get(Integer.valueOf(pos));
			return xwpfRun;
		} else if (path.startsWith("t")) {
			String[] nodes = path.split(">");
			String tNode = nodes[0];
			String rowNode = nodes[1];
			String cNode = nodes[2];
			String pNode = nodes[3];
			String rNode = nodes[4];
			int tPos = Integer.valueOf(tNode.split(":")[1]);
			int rowPos = Integer.valueOf(rowNode.split(":")[1]);
			int cPos = Integer.valueOf(cNode.split(":")[1]);
			int pPos = Integer.valueOf(pNode.split(":")[1]);
			int rPos = Integer.valueOf(rNode.split(":")[1]);
			return document.getTables().get(tPos).getRow(rowPos).getCell(cPos)
					.getParagraphs().get(pPos).getRuns().get(rPos);

		}
		return null;

	}
}
